home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Memory / MemPtchM.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  17.1 KB  |  586 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MemPtchM.cpp
  3.  
  4.     Contains:    Code to make MacOS memory routines call this memory manager
  5.  
  6.     Owned by:    Jens Alfke (based on code by Troy Gaul)
  7.  
  8.     Copyright:    © 1995 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <3>    27.09.1996    NP        1386083: Changes to NewPtr patch
  13.          <1>     6/19/96    jpa        first checked in
  14.     
  15.     In Progress:
  16.     
  17. */
  18.  
  19.  
  20. #include "MemMgr.h"
  21.  
  22. #include "PlatfMem.h"
  23. #include "MemMgrPv.h"
  24.  
  25. #include <CodeFragments.h>
  26. #include <MixedMode.h>
  27. #include <Traps.h>
  28.  
  29.  
  30. //==============================================================================
  31. //    Debugging support
  32. //==============================================================================
  33.  
  34. #define WARN_ON_PATCH_CALL 0    // Set to 1 to break on every patch call
  35.  
  36. #define PATCH_WARN    \
  37.     if(!MM_DEBUG || !WARN_ON_PATCH_CALL) ; else MM_SHOW_WARNING
  38.  
  39.  
  40. //==============================================================================
  41. //    Constants / Types
  42. //==============================================================================
  43.  
  44. const Size   kSizeThreshold = 0;            // Min block size to allocate with MMM
  45. const OSType kTag           = 'ø∫pt';        // Magic tag at start of block
  46.  
  47. // Typedef of private SetEmulatorRegister SPI call:
  48. typedef void (*SetEmulatorRegisterProcPtr) ( registerSelectorType, long newValue );
  49.  
  50.  
  51. //==============================================================================
  52. //    Structs
  53. //==============================================================================
  54.  
  55. struct BlockHeader {
  56.     Size    size;        // Logical size of block (MMM only knows physical size)
  57.     OSType    tag;        // Magic tag (kTag) to detect if this is a block I allocated
  58. };
  59.  
  60. #define HEADER_OF_BLOCK(B)    ((BlockHeader*)((char*)(B)-sizeof(BlockHeader)))
  61. #define BLOCK_OF_HEADER(H)    ((void*)((char*)(H)+sizeof(BlockHeader)))
  62.  
  63.  
  64. //——————————————————————————————————————————————————————————————————————————————
  65. //    Global Variables
  66. //——————————————————————————————————————————————————————————————————————————————
  67.  
  68. static MemHeap* gOSHeap = kMMNULL;
  69.  
  70. static long        gOverridePtrs = 0;
  71. static long        gOverrideHandles = 0;
  72.  
  73. #if GENERATINGPOWERPC
  74. SetEmulatorRegisterProcPtr gSetEmulatorRegisterAddr = kMMNULL;
  75. #endif
  76.  
  77. static UniversalProcPtr gNewHandleAddress  = NULL;
  78. static UniversalProcPtr gNewPtrAddress     = NULL;
  79. static UniversalProcPtr gDisposePtrAddress = NULL;
  80. static UniversalProcPtr gGetPtrSizeAddress = NULL;
  81. static UniversalProcPtr gSetPtrSizeAddress = NULL;
  82. static UniversalProcPtr gMaxBlockAddress   = NULL;
  83. static UniversalProcPtr gPtrZoneAddress    = NULL;
  84.  
  85. #if MM_DEBUG
  86. long gNewPtrBlockCount = 0;
  87. #endif
  88.  
  89.  
  90. //——————————————————————————————————————————————————————————————————————————————
  91. //    ProcInfos
  92. //——————————————————————————————————————————————————————————————————————————————
  93.  
  94. enum
  95. {
  96.     uppNewHandleProcInfo
  97.         = kRegisterBased
  98.             | RESULT_SIZE(SIZE_CODE(sizeof(Handle)))
  99.             | REGISTER_RESULT_LOCATION(kRegisterA0)
  100.             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
  101.             | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size)))
  102.     ,
  103.     uppNewPtrProcInfo
  104.         = kRegisterBased
  105.             | RESULT_SIZE(SIZE_CODE(sizeof(Ptr)))
  106.             | REGISTER_RESULT_LOCATION(kRegisterA0)
  107.             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
  108.             | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size)))
  109.     ,
  110.     uppDisposePtrProcInfo
  111.         = kRegisterBased
  112.             | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
  113.             | REGISTER_RESULT_LOCATION(kRegisterD0)
  114.             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
  115.             | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
  116.     ,
  117.     uppGetPtrSizeProcInfo
  118.         = kRegisterBased
  119.             | RESULT_SIZE(SIZE_CODE(sizeof(Size)))
  120.             | REGISTER_RESULT_LOCATION(kRegisterD0)
  121.             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
  122.             | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
  123.     ,
  124.     uppSetPtrSizeProcInfo
  125.         = kRegisterBased
  126.             | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
  127.             | REGISTER_RESULT_LOCATION(kRegisterD0)
  128.             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
  129.             | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
  130.             | REGISTER_ROUTINE_PARAMETER(3, kRegisterD0, SIZE_CODE(sizeof(Size)))
  131.     ,
  132.     uppMaxBlockProcInfo
  133.         = kRegisterBased
  134.             | RESULT_SIZE(SIZE_CODE(sizeof(long)))
  135.             | REGISTER_RESULT_LOCATION(kRegisterD0)
  136.             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
  137.     ,
  138.     uppPtrZoneProcInfo
  139.         = kRegisterBased
  140.             | RESULT_SIZE(SIZE_CODE(sizeof(THz)))
  141.             | REGISTER_RESULT_LOCATION(kRegisterA0)
  142.             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(unsigned short)))
  143.             | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
  144. };
  145.  
  146.  
  147. //——————————————————————————————————————————————————————————————————————————————
  148. //    FindEmulatorCall
  149. //——————————————————————————————————————————————————————————————————————————————
  150.  
  151. // From MixedModePriv.h:
  152. // extern long SetEmulatorRegister(registerSelectorType registerSelector, long newValue);
  153.  
  154. #if GENERATINGPOWERPC
  155. static OSErr
  156. FindEmulatorCall( )
  157. {
  158.     CFragConnectionID conn;
  159.     Ptr mainAddr;
  160.     Str255 errName;
  161.     OSErr err;
  162.     err = GetSharedLibrary("\pPrivateInterfaceLib",kCurrentCFragArch,kLoadLib,
  163.                             &conn,&mainAddr,errName);
  164.     if( err ) return err;
  165.     
  166.     SymClass symClass;
  167.     err= FindSymbol(conn,"\pSetEmulatorRegister",(Ptr*)&gSetEmulatorRegisterAddr,&symClass);
  168.     
  169.     CloseConnection(&conn);
  170.     return err;
  171. }
  172. #endif
  173.  
  174.  
  175. //——————————————————————————————————————————————————————————————————————————————
  176. //    SetStatus
  177. //——————————————————————————————————————————————————————————————————————————————
  178. static void
  179. SetStatus( OSErr status )
  180. {
  181.     // Used by NewHandle, NewPtr and PtrZone, which return error codes in D0.
  182.     LMSetMemErr(status);
  183. #if GENERATINGPOWERPC
  184.     (*gSetEmulatorRegisterAddr)(kRegisterD0,status);
  185. #endif
  186. }
  187.  
  188.  
  189. //——————————————————————————————————————————————————————————————————————————————
  190. //    NewHandlePatch
  191. //——————————————————————————————————————————————————————————————————————————————
  192.  
  193. static pascal Handle
  194. NewHandlePatch(unsigned short trapWord, Size byteCount)
  195. {
  196.     Handle result;
  197.     if( gOverrideHandles>0
  198.             && (trapWord == _NewHandle || trapWord == _NewHandleClear)
  199.             && byteCount >= kSizeThreshold
  200.             && GetZone()==ApplicationZone() ) {
  201.  
  202.         long temp = gOverrideHandles;        // Temporarily disable to avoid infinite regress
  203.         gOverrideHandles = 0;
  204.         
  205.         result= (Handle) MMAllocateHandleIn(sizeof(BlockHeader) + byteCount, kMMTempMemory);
  206.  
  207.         gOverrideHandles = temp;
  208.     
  209.         if( result ) {
  210.             if( trapWord == _NewHandleClear )
  211.                 PlatformZapMem(*result,byteCount,0);
  212.             SetStatus(noErr);
  213.             PATCH_WARN("NewHandle(%ld) = %p",byteCount,result);
  214.             return result;
  215.         } else
  216.             MM_WARN("NewHandle(%ld) FAILED; trying app heap...",byteCount);
  217.         // If allocation in temp mem failed, try the app heap...
  218.     }
  219.     
  220.     result= (Handle)CallOSTrapUniversalProc(gNewHandleAddress, uppNewHandleProcInfo, 
  221.                                                trapWord, byteCount);
  222. #if GENERATINGPOWERPC
  223.     SetStatus(MemError());
  224. #endif
  225.  
  226.     return result;
  227. }
  228. #if MM_DEBUG
  229. //——————————————————————————————————————————————————————————————————————————————
  230. //    SetNewPtrMemFullMark
  231. //——————————————————————————————————————————————————————————————————————————————
  232.  
  233. mmboolean    gNewPtrPatchMemFullMark = false; // 0 means no mark.
  234.  
  235. void MMSetPlatformBlockMemFullMark()
  236. {
  237.     gNewPtrPatchMemFullMark = true;
  238. }
  239.  
  240. void MMUnsetPlatformBlockMemFullMark()
  241. {
  242.     gNewPtrPatchMemFullMark = false;
  243. }
  244. #endif /* MM_DEBUG */
  245. //——————————————————————————————————————————————————————————————————————————————
  246. //    NewPtrPatch
  247. //——————————————————————————————————————————————————————————————————————————————
  248.  
  249. static pascal Ptr
  250. NewPtrPatch(unsigned short trapWord, Size byteCount)
  251. {
  252. #if MM_DEBUG
  253.     if (gNewPtrPatchMemFullMark)
  254.         return 0;
  255. #endif
  256.     Ptr result;
  257.     if( gOverridePtrs>0
  258.             && (trapWord == _NewPtr || trapWord == _NewPtrClear)
  259.             && byteCount >= kSizeThreshold
  260.             && GetZone()==ApplicationZone() ) {
  261.  
  262.         BlockHeader *header;
  263.         if (trapWord == _NewPtr)
  264.             header = (BlockHeader*) MMAllocateIn(sizeof(BlockHeader) + byteCount, gOSHeap);
  265.         else
  266.             header = (BlockHeader*) MMAllocateClearIn(sizeof(BlockHeader) + byteCount, gOSHeap);
  267.  
  268.         if( header ) {
  269.             header->tag = kTag;
  270.             header->size = byteCount;
  271.             result = (Ptr) BLOCK_OF_HEADER(header);
  272.             #if MM_DEBUG
  273.             gNewPtrBlockCount++;
  274.             #endif
  275.             SetStatus(noErr);
  276.             PATCH_WARN("NewPtr(%ld) = %p",byteCount,result);
  277.             return result;
  278.         } else
  279.             MM_WARN("NewPtr(%ld) FAILED; trying app heap...",byteCount);
  280.         // If allocation in temp mem failed, try the app heap...
  281.     }
  282.         
  283.     result= (Ptr)CallOSTrapUniversalProc(gNewPtrAddress, uppNewPtrProcInfo, 
  284.                                                trapWord, byteCount);
  285. #if GENERATINGPOWERPC
  286.     SetStatus(MemError());
  287. #endif
  288.  
  289.     return result;
  290. }
  291.  
  292.  
  293. //——————————————————————————————————————————————————————————————————————————————
  294. //    DisposePtrPatch
  295. //——————————————————————————————————————————————————————————————————————————————
  296. static pascal OSErr
  297. DisposePtrPatch(unsigned short trapWord, Ptr p)
  298. {
  299.     BlockHeader *h = HEADER_OF_BLOCK(p);
  300.     if (p && h->tag == kTag)
  301.     {
  302.         PATCH_WARN("DisposePtr(%p);g",p);
  303.         h->tag = 0xDDDD;                // Minimizes chance this will look like a block later
  304.         MMFree(h);
  305.         LMSetMemErr(noErr);
  306.         #if MM_DEBUG
  307.         gNewPtrBlockCount--;
  308.         if( gNewPtrBlockCount==-1 ) MM_WARN("Too many NewPtr blocks disposed!?!?");
  309.         #endif
  310.         return noErr;
  311.     }
  312.     else
  313.     {
  314.         return CallOSTrapUniversalProc(gDisposePtrAddress, uppDisposePtrProcInfo, 
  315.                                 trapWord, p);
  316.     }
  317. }
  318.  
  319.  
  320. //——————————————————————————————————————————————————————————————————————————————
  321. //    GetPtrSizePatch
  322. //——————————————————————————————————————————————————————————————————————————————
  323. static pascal Size
  324. GetPtrSizePatch(unsigned short trapWord, Ptr p)
  325. {
  326.     BlockHeader *h = HEADER_OF_BLOCK(p);
  327.     if (p && h->tag == kTag)
  328.     {
  329.         PATCH_WARN("GetPtrSize(%p)",p);
  330.         LMSetMemErr(noErr);
  331.         return h->size;
  332.     }
  333.     else
  334.     {
  335.         return CallOSTrapUniversalProc(gGetPtrSizeAddress, uppGetPtrSizeProcInfo, 
  336.                                 trapWord, p);
  337.     }
  338. }
  339.  
  340.  
  341. //——————————————————————————————————————————————————————————————————————————————
  342. //    SetPtrSizePatch
  343. //——————————————————————————————————————————————————————————————————————————————
  344. static pascal OSErr
  345. SetPtrSizePatch(unsigned short trapWord, Ptr p, Size newSize)
  346. {
  347.     BlockHeader *h = HEADER_OF_BLOCK(p);
  348.     if (p && h->tag == kTag)
  349.     {
  350.         // Our memory manager lacks a way to grow a block into an adjacent free
  351.         // block. This is probably not a big deal. Grow it as much as it can:
  352.         PATCH_WARN("SetPtrSize(%p,%ld)",p,newSize);
  353.         OSErr err;
  354.         if( newSize <= MMBlockSize(h) ) {
  355.             h->size = newSize;
  356.             err= noErr;
  357.         } else
  358.             err= memFullErr;
  359.         LMSetMemErr(err);
  360.         return err;
  361.     }
  362.     else
  363.     {
  364.         return CallOSTrapUniversalProc(gSetPtrSizeAddress, uppSetPtrSizeProcInfo, 
  365.                                 trapWord, p, newSize);
  366.     }
  367. }
  368.  
  369.  
  370. //——————————————————————————————————————————————————————————————————————————————
  371. //    MaxBlockPatch
  372. //——————————————————————————————————————————————————————————————————————————————
  373. static pascal long 
  374. MaxBlockPatch( unsigned short trapWord )
  375. {
  376.     Size space = (Size) CallOSTrapUniversalProc(gMaxBlockAddress, uppMaxBlockProcInfo,
  377.                                 trapWord);
  378.     if( GetZone()==ApplicationZone() ) {
  379.         PATCH_WARN("MaxBlock()");
  380.  
  381.     Size unused;
  382.     Size tempSpace = TempMaxMem(&unused);
  383.         if( tempSpace > space )
  384.             space = tempSpace;
  385.     }
  386.     return space;
  387. }
  388.  
  389.  
  390. //——————————————————————————————————————————————————————————————————————————————
  391. //    PtrZonePatch
  392. //——————————————————————————————————————————————————————————————————————————————
  393. static pascal THz 
  394. PtrZonePatch(unsigned short trapword, Ptr p)
  395. {
  396.     BlockHeader *h = HEADER_OF_BLOCK(p);
  397.     if (p && h->tag == kTag)
  398.     {
  399.         // Not much we can do here but lie, since the actual zone is not a MacOS
  400.         // zone in any sense. But we know the block _would_ have been in the app zone:
  401.         PATCH_WARN("PtrZone(%p)",p);
  402.         return ApplicationZone();
  403.         SetStatus(noErr);
  404.     }
  405.     else
  406.     {
  407.         return (THz) CallOSTrapUniversalProc(gPtrZoneAddress, uppPtrZoneProcInfo, 
  408.                                 trapword, p);
  409.         SetStatus(MemError());
  410.     }
  411. }
  412.  
  413.  
  414. //——————————————————————————————————————————————————————————————————————————————
  415. //    Routine descriptors
  416. //——————————————————————————————————————————————————————————————————————————————
  417.  
  418. static RoutineDescriptor NewHandlePatchRD
  419.                 = BUILD_ROUTINE_DESCRIPTOR(uppNewHandleProcInfo, NewHandlePatch);
  420.  
  421. static RoutineDescriptor NewPtrPatchRD
  422.                 = BUILD_ROUTINE_DESCRIPTOR(uppNewPtrProcInfo, NewPtrPatch);
  423.  
  424. static RoutineDescriptor DisposePtrPatchRD
  425.                 = BUILD_ROUTINE_DESCRIPTOR(uppDisposePtrProcInfo, DisposePtrPatch);
  426.  
  427. static RoutineDescriptor GetPtrSizePatchRD
  428.                 = BUILD_ROUTINE_DESCRIPTOR(uppGetPtrSizeProcInfo, GetPtrSizePatch);
  429.  
  430. static RoutineDescriptor SetPtrSizePatchRD
  431.                 = BUILD_ROUTINE_DESCRIPTOR(uppSetPtrSizeProcInfo, SetPtrSizePatch);
  432.  
  433. static RoutineDescriptor MaxBlockPatchRD
  434.                 = BUILD_ROUTINE_DESCRIPTOR(uppMaxBlockProcInfo, MaxBlockPatch);
  435.  
  436. static RoutineDescriptor PtrZonePatchRD
  437.                 = BUILD_ROUTINE_DESCRIPTOR(uppPtrZoneProcInfo, PtrZonePatch);
  438.  
  439.  
  440. #if GENERATING68K
  441. /*
  442.     What the heck is this stuff? On 68K we have some headaches trying to patch
  443.     NewPtr, which returns two values: the pointer in A0 and an OSErr in D0.
  444.     MixedMode only allows one return value. To work around this on 68K, the
  445.     _real_ trap patch will be classic non-CFM 68K assembly which calls the CFM
  446.     patch (NewPtrPatch) through a RoutineDescriptor, then sets D0.
  447.     A gotcha here is that the value in the RoutineDescriptor is different for
  448.     different CFM contexts, since it points to a TVector. This makes sense,
  449.     since NewPtrPatch has to reference the global gOSHeap. To allow this,
  450.     we can't use normal code since it's shared. So we force the stub to be
  451.     generated in the global data space, which is per-context. Hence the hand
  452.     assembly below.
  453. */
  454.  
  455.     #if PRAGMA_ALIGN_SUPPORTED
  456.     #pragma options align=mac68k
  457.     #endif
  458.     
  459.     struct PatchWrapper {
  460.         short code1[1];
  461.         UniversalProcPtr upp;
  462.         short code2[4];
  463.     };
  464.     
  465.     static PatchWrapper gNewHandlePatch = {
  466.             {0x4EB9}, &NewHandlePatchRD,    // jsr        &NewHandlePatchRD
  467.             {0x3038, 0x0220,                // move.w    MemErr,D0
  468.              0x48C0,                        // ext.l    D0
  469.              0x4E75}                        // rts
  470.         };
  471.     static PatchWrapper gNewPtrPatch = {
  472.             {0x4EB9}, &NewPtrPatchRD,        // jsr        &NewPtrPatchRD
  473.             {0x3038, 0x0220,                // move.w    MemErr,D0
  474.              0x48C0,                        // ext.l    D0
  475.              0x4E75}                        // rts
  476.         };
  477.     static PatchWrapper gPtrZonePatch = {
  478.             {0x4EB9}, &PtrZonePatchRD,        // jsr        &PtrZonePatchRD
  479.             {0x3038, 0x0220,                // move.w    MemErr,D0
  480.              0x48C0,                        // ext.l    D0
  481.              0x4E75}                        // rts
  482.         };
  483.         
  484.     #if PRAGMA_ALIGN_SUPPORTED
  485.     #pragma options align=reset
  486.     #endif
  487. #endif
  488.  
  489.  
  490. //——————————————————————————————————————————————————————————————————————————————
  491. //    MMOverridePlatform
  492. //——————————————————————————————————————————————————————————————————————————————
  493. void
  494. MMOverridePlatform( MMBoolean ptrs, MMBoolean handles )
  495. {
  496.     if( ptrs ) {
  497.         gOverridePtrs++;
  498.         if( gNewPtrAddress == kMMNULL ) {
  499.             
  500.             // Install patches 1st time called:
  501.             #if GENERATINGPOWERPC
  502.                 OSErr err= FindEmulatorCall();
  503.                 if( err != noErr ) {
  504.                     MM_WARN("Couldn't find SetEmulatorRegister, err %d",err);
  505.                     return;
  506.                 }
  507.             #endif
  508.                 
  509.             gOSHeap = MMGetDefaultHeap();
  510.             
  511.             gNewPtrAddress        = GetOSTrapAddress(_NewPtr);
  512.             gPtrZoneAddress        = GetOSTrapAddress(_PtrZone);
  513.             gDisposePtrAddress    = GetOSTrapAddress(_DisposePtr);
  514.             gGetPtrSizeAddress    = GetOSTrapAddress(_GetPtrSize);
  515.             gSetPtrSizeAddress    = GetOSTrapAddress(_SetPtrSize);
  516. //            gMaxBlockAddress    = GetOSTrapAddress(_MaxBlock);
  517.  
  518.             #if GENERATING68K
  519.                 SetOSTrapAddress((UniversalProcPtr) &gNewPtrPatch,     _NewPtr);
  520.                 SetOSTrapAddress((UniversalProcPtr) &gPtrZonePatch,     _PtrZone);
  521.             #else
  522.                 SetOSTrapAddress((UniversalProcPtr) &NewPtrPatchRD,    _NewPtr);
  523.                 SetOSTrapAddress((UniversalProcPtr) &PtrZonePatchRD,   _PtrZone);
  524.             #endif
  525.             SetOSTrapAddress((UniversalProcPtr) &DisposePtrPatchRD, _DisposePtr);
  526.             SetOSTrapAddress((UniversalProcPtr) &GetPtrSizePatchRD, _GetPtrSize);
  527.             SetOSTrapAddress((UniversalProcPtr) &SetPtrSizePatchRD, _SetPtrSize);
  528.         //    SetOSTrapAddress((UniversalProcPtr) &MaxBlockPatchRD, _MaxBlock);
  529.  
  530.             #if GENERATING68K
  531.             #else
  532.             #endif
  533.         }
  534.     }
  535.     
  536.     if( handles ) {
  537.         gOverrideHandles++;
  538.         if( gNewHandleAddress == kMMNULL ) {
  539.             gNewHandleAddress = GetOSTrapAddress(_NewHandle);
  540.             #if GENERATING68K
  541.                 SetOSTrapAddress((UniversalProcPtr) &gNewHandlePatch, _NewHandle);
  542.             #else
  543.                 SetOSTrapAddress((UniversalProcPtr) &NewHandlePatchRD, _NewHandle);
  544.             #endif
  545.             
  546. /*            MM_WARN("Testing handles...");
  547.             Handle h = NewHandle(1234);
  548.             MM_WARN("Handle is at %p",h);
  549.             DisposeHandle(h);
  550.             MM_WARN("...Done testing handles.");*/
  551.         }
  552.     }
  553. }
  554.  
  555.  
  556. //——————————————————————————————————————————————————————————————————————————————
  557. //    MMEndOverridePlatform
  558. //——————————————————————————————————————————————————————————————————————————————
  559. void
  560. MMEndOverridePlatform( MMBoolean ptrs, MMBoolean handles )
  561. {
  562.     if( ptrs ) {
  563.         if( gOverridePtrs > 0 )
  564.             gOverridePtrs--;
  565.         else
  566.             MM_WARN("Too many MMEndOverridePlatform(true,...)");
  567.     }
  568.     if( handles ) {
  569.         if( gOverrideHandles > 0 )
  570.             gOverrideHandles--;
  571.         else
  572.             MM_WARN("Too many MMEndOverridePlatform(...,true)");
  573.     }
  574. }
  575.  
  576.  
  577. //——————————————————————————————————————————————————————————————————————————————
  578. //    MMOverridingPlatform
  579. //——————————————————————————————————————————————————————————————————————————————
  580. void
  581. MMOverridingPlatform( MMBoolean *ptrs, MMBoolean *handles )
  582. {
  583.     if( ptrs )        *ptrs    = (gOverridePtrs>0);
  584.     if( handles )    *handles = (gOverrideHandles>0);
  585. }
  586.